﻿#include "QCefDelegate.h"
#include "QCefWidget.h"
#include "QCefStrResFilter.h"

QCefDelegate::QCefDelegate(QCefWidget * opr)
{
    QCEF_DEBUG();

    this->setOperator(opr);
}

QCefDelegate::~QCefDelegate()
{
    QCEF_DEBUG();

    finiDelegate();
}

int QCefDelegate::finiDelegate()
{
    this->setOperator(nullptr);

    return 0;
}


//////////////////////////////////////////////////////////////////////////
//CefClient
bool QCefDelegate::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
                                              CefRefPtr<CefFrame> frame,
                                              CefProcessId source_process,
                                              CefRefPtr<CefProcessMessage> message)
{
    QCEF_DEBUG();

    OPERATOR_CLASS * opr = m_operator.loadAcquire();
    if (opr == nullptr)
    {
        return false;
    }

    //
    QString strMsgName = QString::fromStdString(message->GetName());

    if (strMsgName == kQCefRenderReportJavaScriptResultMessage)
    {
        // validate the argument list
        CefRefPtr<CefListValue> arguments = message->GetArgumentList();
        if (arguments != nullptr && (arguments->GetSize() == 2))
        {
            // get the JS result
            int id = arguments->GetInt(0);

            CefRefPtr<CefValue> result = arguments->GetValue(1);
            QVariant ret;
            CefValueToQVariant(ret, result);

            opr->pageReportJavaScriptResult(id, ret);
        }
    }
    else if (strMsgName == kCefViewClientRenderFocusedNodeChangedMessage)
    {
        // validate the argument list
        CefRefPtr<CefListValue> arguments = message->GetArgumentList();
        if (arguments != nullptr && (arguments->GetSize() >= 1))
        {
            bool focusOnEditableField = message->GetArgumentList()->GetBool(0);

            opr->pageFocusedEditableNodeChanged(focusOnEditableField);
        }
    }

    return true;
}


//////////////////////////////////////////////////////////////////////////
//CefLifeSpanHandler
bool QCefDelegate::OnBeforePopup(CefRefPtr<CefBrowser> browser,
                                CefRefPtr<CefFrame> frame,
                                const CefString& target_url,
                                const CefString& target_frame_name,
                                CefLifeSpanHandler::WindowOpenDisposition target_disposition,
                                bool user_gesture,
                                const CefPopupFeatures& popupFeatures,
                                CefWindowInfo& windowInfo,
                                CefRefPtr<CefClient>& client,
                                CefBrowserSettings& settings,
                                CefRefPtr<CefDictionaryValue>& extra_info,
                                bool* no_javascript_access)
{
    QCEF_DEBUG();

    OPERATOR_CLASS * opr = m_operator.loadAcquire();
    if (opr != nullptr)
    {
        QString strUrl = QString::fromStdString(target_url.ToString());
        QString strTitle = QString::fromStdString(target_frame_name.ToString());

        opr->pageBeforePopup(strUrl, strTitle, (int)target_disposition, user_gesture);
    }

    //false: 允许弹窗；true: 不允许弹窗
    return true;
}

void QCefDelegate::OnAfterCreated(CefRefPtr<CefBrowser> browser)
{
    QCEF_DEBUG();

    //
    OPERATOR_CLASS * opr = m_operator.loadAcquire();
    if (opr != nullptr)
    {
        opr->browserCreated(browser);

        opr->pageAfterCreated();
    }
}


bool QCefDelegate::DoClose(CefRefPtr<CefBrowser> browser)
{
    QCEF_DEBUG();

    OPERATOR_CLASS * opr = m_operator.loadAcquire();
    if (opr != nullptr)
    {
        opr->pageDoClose();
    }

    return false;
}

void QCefDelegate::OnBeforeClose(CefRefPtr<CefBrowser> browser)
{
    QCEF_DEBUG();

    OPERATOR_CLASS * opr = m_operator.loadAcquire();
    if (opr != nullptr)
    {
        opr->pageBeforeClose();
    }
}


//////////////////////////////////////////////////////////////////////////
//CefLoadHandler
void QCefDelegate::OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
                                              bool isLoading,
                                              bool canGoBack,
                                              bool canGoForward)
{
    QCEF_DEBUG();

    OPERATOR_CLASS * opr = m_operator.loadAcquire();
    if (opr != nullptr && !browser->IsPopup())
    {
        opr->pageLoadingStateChange(isLoading, canGoBack, canGoForward);
    }
}

void QCefDelegate::OnLoadStart(CefRefPtr<CefBrowser> browser,
                                     CefRefPtr<CefFrame> frame,
                                     CefLoadHandler::TransitionType transition_type)
{
    QCEF_DEBUG();

    OPERATOR_CLASS * opr = m_operator.loadAcquire();
    if (opr != nullptr && !browser->IsPopup() && frame->IsMain())
    {
        opr->pageLoadStart((int)transition_type);
    }
}


void QCefDelegate::OnLoadEnd(CefRefPtr<CefBrowser> browser,
                                   CefRefPtr<CefFrame> frame,
                                   int httpStatusCode)
{
    QCEF_DEBUG();

    OPERATOR_CLASS * opr = m_operator.loadAcquire();
    if (opr != nullptr && !browser->IsPopup() && frame->IsMain())
    {
        opr->pageLoadEnd(httpStatusCode);
    }
}


void QCefDelegate::OnLoadError(CefRefPtr<CefBrowser> browser,
                                     CefRefPtr<CefFrame> frame,
                                     CefLoadHandler::ErrorCode errorCode,
                                     const CefString& errorText,
                                     const CefString& failedUrl)
{
    QCEF_DEBUG();

    OPERATOR_CLASS * opr = m_operator.loadAcquire();
    if (opr != nullptr && !browser->IsPopup() && frame->IsMain())
    {
        QString strErrorText = QString::fromStdString(errorText.ToString());
        QString strFailedUrl = QString::fromStdString(failedUrl.ToString());

        opr->pageLoadError((int)errorCode, strErrorText, strFailedUrl);
    }
}


#pragma endregion CefLoadHandler


//////////////////////////////////////////////////////////////////////////
//CefDisplayHandler
void QCefDelegate::OnAddressChange(CefRefPtr<CefBrowser> browser,
                                         CefRefPtr<CefFrame> frame,
                                         const CefString & url)
{
    QCEF_DEBUG();

    OPERATOR_CLASS * opr = m_operator.loadAcquire();
    if (opr != nullptr && !browser->IsPopup() && frame->IsMain())
    {
        QString strUrl = QString::fromStdString(url.ToString());

        opr->pageAddressChange(strUrl);
    }
}

void QCefDelegate::OnTitleChange(CefRefPtr<CefBrowser> browser,
                                       const CefString & title)
{
    QCEF_DEBUG();

    OPERATOR_CLASS * opr = m_operator.loadAcquire();
    if (opr != nullptr && !browser->IsPopup())
    {
        QString strTitle = QString::fromStdString(title.ToString());

        opr->pageTitleChange(strTitle);
    }
}


void QCefDelegate::OnFaviconURLChange(CefRefPtr<CefBrowser> browser,
                                            const std::vector<CefString>& icon_urls)
{
    QCEF_DEBUG();

    OPERATOR_CLASS * opr = m_operator.loadAcquire();
    if (opr != nullptr && !browser->IsPopup())
    {
        QStringList urls;
        for (auto& iconUrl : icon_urls)
        {
            urls.append(QString::fromStdString(iconUrl.ToString()));
        }

        opr->pageFaviconURLChange(urls);
    }
}


void QCefDelegate::OnFullscreenModeChange(CefRefPtr<CefBrowser> browser,
                                                bool fullscreen)
{
    QCEF_DEBUG();

    OPERATOR_CLASS * opr = m_operator.loadAcquire();
    if (opr != nullptr && !browser->IsPopup())
    {
        opr->pageFullscreenModeChange(fullscreen);
    }
}


bool QCefDelegate::OnTooltip(CefRefPtr<CefBrowser> browser, CefString& text)
{
    QCEF_DEBUG();

    OPERATOR_CLASS * opr = m_operator.loadAcquire();
    if (opr != nullptr && !browser->IsPopup())
    {
        QString strText = QString::fromStdString(text.ToString());

        opr->pageTooltip(strText);
    }

    return false;
}


void QCefDelegate::OnStatusMessage(CefRefPtr<CefBrowser> browser,
                                         const CefString& value)
{
    QCEF_DEBUG();

    OPERATOR_CLASS * opr = m_operator.loadAcquire();
    if (opr != nullptr && !browser->IsPopup())
    {
        QString strValue = QString::fromStdString(value.ToString());

        opr->pageStatusMessage(strValue);
    }
}


bool QCefDelegate::OnConsoleMessage(CefRefPtr<CefBrowser> browser,
                                          cef_log_severity_t level,
                                          const CefString& message,
                                          const CefString& source,
                                          int line)
{
    QCEF_DEBUG();

    OPERATOR_CLASS * opr = m_operator.loadAcquire();
    if (opr != nullptr && !browser->IsPopup())
    {
        QString strMessage = QString::fromStdString(message.ToString());
        QString strSource = QString::fromStdString(source.ToString());

        opr->pageConsoleMessage(level, strMessage, strSource, line);
    }

    return false;
}


bool QCefDelegate::OnAutoResize(CefRefPtr<CefBrowser> browser,
                                      const CefSize & new_size)
{
    QCEF_DEBUG();

    OPERATOR_CLASS * opr = m_operator.loadAcquire();
    if (opr != nullptr && !browser->IsPopup())
    {
        QSize sz(new_size.width, new_size.height);

        opr->pageAutoResize(sz);
    }

    return false;
}


void QCefDelegate::OnLoadingProgressChange(CefRefPtr<CefBrowser> browser,
                                                 double progress)
{
    QCEF_DEBUG();

    OPERATOR_CLASS * opr = m_operator.loadAcquire();
    if (opr != nullptr && !browser->IsPopup())
    {
        opr->pageLoadingProgressChange(progress);
    }
}


bool QCefDelegate::OnCursorChange(CefRefPtr<CefBrowser> browser,
                                        CefCursorHandle cursor,
                                        cef_cursor_type_t type,
                                        const CefCursorInfo& custom_cursor_info)
{
    QCEF_DEBUG();

    OPERATOR_CLASS * opr = m_operator.loadAcquire();
    if (opr != nullptr)
    {
        opr->pageCursorChange((int)type);
    }

    return false;
}

void QCefDelegate::OnFaviconChange(const CefString & image_url,
                                int http_status_code,
                                CefRefPtr<CefImage> image)
{
    QCEF_DEBUG();

    OPERATOR_CLASS * opr = m_operator.loadAcquire();
    if (opr != nullptr)
    {
        QString strImageUrl = QString::fromStdString(image_url.ToString());
        QIcon icon = CefImageToQIcon(image);

        opr->pageFaviconChange(strImageUrl, http_status_code, icon);
    }
}


//////////////////////////////////////////////////////////////////////////
//CefFocusHandler
void QCefDelegate::OnTakeFocus(CefRefPtr<CefBrowser> browser, bool next)
{
    QCEF_DEBUG();

    OPERATOR_CLASS * opr = m_operator.loadAcquire();
    if (opr != nullptr)
    {
        opr->pageTakeFocus(next);
    }
}

bool QCefDelegate::OnSetFocus(CefRefPtr<CefBrowser> browser, CefFocusHandler::FocusSource source)
{
    QCEF_DEBUG();

    OPERATOR_CLASS * opr = m_operator.loadAcquire();
    if (opr != nullptr)
    {
        opr->pageSetFocus((int)source);
    }

    return false;
}

void QCefDelegate::OnGotFocus(CefRefPtr<CefBrowser> browser)
{
    QCEF_DEBUG();

    OPERATOR_CLASS * opr = m_operator.loadAcquire();
    if (opr != nullptr)
    {
        opr->pageGotFocus();
    }
}


//////////////////////////////////////////////////////////////////////////
//CefRenderHandler
CefRefPtr<CefAccessibilityHandler> QCefDelegate::GetAccessibilityHandler()
{
    QCEF_DEBUG();

    return nullptr;
}

bool QCefDelegate::GetRootScreenRect(CefRefPtr<CefBrowser> browser, CefRect& rect)
{
    QCEF_DEBUG();

    OPERATOR_CLASS * opr = m_operator.loadAcquire();
    if (opr != nullptr)
    {
        // get the screen which the view is currently residing in
        QScreen* screen = opr->screen();
        if (!screen)
        {
            // the view is not visible so we retrieve the main screen info
            screen = QApplication::screens().at(0);
        }

        QRect rt = screen->geometry();

        rect.Set(rt.x(), rt.y(), rt.width(), rt.height());

        return true;
    }

    return false;
}

void QCefDelegate::GetViewRect(CefRefPtr<CefBrowser> browser, CefRect& rect)
{
    QCEF_DEBUG();

    OPERATOR_CLASS * opr = m_operator.loadAcquire();
    if (opr != nullptr)
    {
        QSize sz = opr->size();

        rect.Set(0, 0, sz.width() ? sz.width() : 1, sz.height() ? sz.height() : 1);
    }
}

bool QCefDelegate::GetScreenPoint(CefRefPtr<CefBrowser> browser,
                                        int viewX,
                                        int viewY,
                                        int& screenX,
                                        int& screenY)
{
    QCEF_DEBUG();

    OPERATOR_CLASS * opr = m_operator.loadAcquire();
    if (opr != nullptr)
    {
        QPoint pt = opr->mapToGlobal(QPoint(viewX, viewY));

        screenX = pt.x();
        screenY = pt.y();

        return true;
    }

    return false;
}

bool QCefDelegate::GetScreenInfo(CefRefPtr<CefBrowser> browser,
                                       CefScreenInfo& screen_info)
{
    QCEF_DEBUG();

    OPERATOR_CLASS * opr = m_operator.loadAcquire();
    if (opr != nullptr)
    {
        // get the screen which the view is currently residing in
        QScreen * screen = opr->screen();
        if (!screen)
        {
            // the view is not visible so we retrieve the main screen info
            screen = QApplication::screens().at(0);
        }

        QRect rect = screen->geometry();
        QRect availableRect = screen->availableGeometry();
        screen_info.Set(screen->devicePixelRatio(),                                                             //
                        screen->depth(),                                                                        //
                        0,                                                                                      //
                        false,                                                                                  //
                        { rect.x(), rect.y(), rect.width(), rect.height() },                                    //
                        { availableRect.x(), availableRect.y(), availableRect.width(), availableRect.height() } //
                        );

        return true;
    }

    return false;
}

void QCefDelegate::OnPopupShow(CefRefPtr<CefBrowser> browser, bool show)
{
    QCEF_DEBUG();

    OPERATOR_CLASS * opr = m_operator.loadAcquire();
    if (opr != nullptr)
    {
        opr->pagePopupShow(show);
    }
}

void QCefDelegate::OnPopupSize(CefRefPtr<CefBrowser> browser, const CefRect& rect)
{
    QCEF_DEBUG();

    OPERATOR_CLASS * opr = m_operator.loadAcquire();
    if (opr != nullptr)
    {
        QRect rt{ rect.x, rect.y, rect.width, rect.height };

        opr->pagePopupSize(rt);
    }
}

void QCefDelegate::OnPaint(CefRefPtr<CefBrowser> browser,
                         CefRenderHandler::PaintElementType type,
                         const CefRenderHandler::RectList& dirtyRects,
                         const void* buffer,
                         int width,
                         int height)
{
    QCEF_DEBUG();

    OPERATOR_CLASS * opr = m_operator.loadAcquire();
    if (opr != nullptr)
    {
        QRegion region;
        for (auto& rect : dirtyRects)
        {
            region += QRect{ rect.x, rect.y, rect.width, rect.height };
        }

        QImage image = QImage(static_cast<const uchar*>(buffer), width, height, QImage::Format_ARGB32_Premultiplied).copy();


        opr->pagePaint((int)type, region, image, width, height);
    }
}

void QCefDelegate::OnAcceleratedPaint(CefRefPtr<CefBrowser> browser,
                                            CefRenderHandler::PaintElementType type,
                                            const CefRenderHandler::RectList& dirtyRects,
                                            void* shared_handle)
{
    QCEF_DEBUG();

    OPERATOR_CLASS * opr = m_operator.loadAcquire();
    if (opr != nullptr)
    {
        QRegion region;
        for (auto& rect : dirtyRects)
        {
            region += QRect{ rect.x, rect.y, rect.width, rect.height };
        }

        opr->pageAcceleratedPaint((int)type, region, shared_handle);
    }
}

bool QCefDelegate::StartDragging(CefRefPtr<CefBrowser> browser,
                                       CefRefPtr<CefDragData> drag_data,
                                       CefRenderHandler::DragOperationsMask allowed_ops,
                                       int x,
                                       int y)
{
    QCEF_DEBUG();

    return false;
}

void QCefDelegate::UpdateDragCursor(CefRefPtr<CefBrowser> browser,
                                          CefRenderHandler::DragOperation operation)
{
    QCEF_DEBUG();
}

void QCefDelegate::OnScrollOffsetChanged(CefRefPtr<CefBrowser> browser,
                                               double x,
                                               double y)
{
    QCEF_DEBUG();

    OPERATOR_CLASS * opr = m_operator.loadAcquire();
    if (opr != nullptr)
    {
        opr->pageScrollOffsetChanged(x, y);
    }
}

void QCefDelegate::OnImeCompositionRangeChanged(CefRefPtr<CefBrowser> browser,
                                                      const CefRange& selected_range,
                                                      const CefRenderHandler::RectList& character_bounds)
{
    QCEF_DEBUG();

    OPERATOR_CLASS * opr = m_operator.loadAcquire();
    if (opr != nullptr)
    {
        //QRegion region;
        //for (auto& rect : character_bounds)
        //{
        //    region += QRect{ rect.x, rect.y, rect.width, rect.height };
        //}

        CefRect r = character_bounds[character_bounds.size() - 1];
        QRect rt(r.x, r.y, r.width, r.height);

        opr->pageImeCompositionRangeChanged(selected_range.from, selected_range.to, rt);
    }
}

void QCefDelegate::OnTextSelectionChanged(CefRefPtr<CefBrowser> browser,
                                                const CefString& selected_text,
                                                const CefRange& selected_range)
{
    QCEF_DEBUG();

    OPERATOR_CLASS * opr = m_operator.loadAcquire();
    if (opr != nullptr)
    {
        QString strSelectedText = QString::fromStdString(selected_text.ToString());

        opr->pageTextSelectionChanged(selected_range.from, selected_range.to, strSelectedText);
    }
}

void QCefDelegate::OnVirtualKeyboardRequested(CefRefPtr<CefBrowser> browser,
                                                    CefRenderHandler::TextInputMode input_mode)
{
    QCEF_DEBUG();

    OPERATOR_CLASS * opr = m_operator.loadAcquire();
    if (opr != nullptr)
    {
        opr->pageVirtualKeyboardRequested((int)input_mode);
    }
}



//////////////////////////////////////////////////////////////////////////
//CefRequestHandler
bool QCefDelegate::OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
                                        CefRefPtr<CefFrame> frame,
                                        CefRefPtr<CefRequest> request,
                                        bool user_gesture,
                                        bool is_redirect)
{
    QCEF_DEBUG();

    return false;
}

bool QCefDelegate::OnOpenURLFromTab(CefRefPtr<CefBrowser> browser,
                                          CefRefPtr<CefFrame> frame,
                                          const CefString& target_url,
                                          CefRequestHandler::WindowOpenDisposition target_disposition,
                                          bool user_gesture)
{
    QCEF_DEBUG();

    return false;
}

CefRefPtr<CefResourceRequestHandler> QCefDelegate::GetResourceRequestHandler(CefRefPtr<CefBrowser> browser,
                                                                                   CefRefPtr<CefFrame> frame,
                                                                                   CefRefPtr<CefRequest> request,
                                                                                   bool is_navigation,
                                                                                   bool is_download,
                                                                                   const CefString& request_initiator,
                                                                                   bool& disable_default_handling)
{
    QCEF_DEBUG();

    return nullptr;
}


bool QCefDelegate::GetAuthCredentials(CefRefPtr<CefBrowser> browser,
                                            const CefString& origin_url,
                                            bool isProxy,
                                            const CefString& host,
                                            int port,
                                            const CefString& realm,
                                            const CefString& scheme,
                                            CefRefPtr<CefAuthCallback> callback)
{
    QCEF_DEBUG();

    return false;
}


bool QCefDelegate::OnQuotaRequest(CefRefPtr<CefBrowser> browser,
                                        const CefString& origin_url,
                                        int64 new_size,
                                        CefRefPtr<CefCallback> callback)
{
    QCEF_DEBUG();

    return false;
}


bool QCefDelegate::OnCertificateError(CefRefPtr<CefBrowser> browser,
                                            cef_errorcode_t cert_error,
                                            const CefString& request_url,
                                            CefRefPtr<CefSSLInfo> ssl_info,
                                            CefRefPtr<CefCallback> callback)
{
    QCEF_DEBUG();

    return false;
}


bool QCefDelegate::OnSelectClientCertificate(CefRefPtr<CefBrowser> browser,
                                                   bool isProxy,
                                                   const CefString& host,
                                                   int port,
                                                   const CefRequestHandler::X509CertificateList& certificates,
                                                   CefRefPtr<CefSelectClientCertificateCallback> callback)
{
    QCEF_DEBUG();

    return false;
}


void QCefDelegate::OnRenderViewReady(CefRefPtr<CefBrowser> browser)
{
    QCEF_DEBUG();
}


void QCefDelegate::OnRenderProcessTerminated(CefRefPtr<CefBrowser> browser,
                                                   CefRequestHandler::TerminationStatus status)
{
    QCEF_DEBUG();
}


void QCefDelegate::OnDocumentAvailableInMainFrame(CefRefPtr<CefBrowser> browser)
{
    QCEF_DEBUG();
}


//////////////////////////////////////////////////////////////////////////
//CefResourceRequestHandler
CefRefPtr<CefCookieAccessFilter> QCefDelegate::GetCookieAccessFilter(CefRefPtr<CefBrowser> browser,
                                                                           CefRefPtr<CefFrame> frame,
                                                                           CefRefPtr<CefRequest> request)
{
    QCEF_DEBUG();

    return nullptr;
}

CefResourceRequestHandler::ReturnValue QCefDelegate::OnBeforeResourceLoad(CefRefPtr<CefBrowser> browser,
                                                                                CefRefPtr<CefFrame> frame,
                                                                                CefRefPtr<CefRequest> request,
                                                                                CefRefPtr<CefCallback> callback)
{
    QCEF_DEBUG();

    OPERATOR_CLASS * opr = m_operator.loadAcquire();
    if (opr != nullptr)
    {
        if (opr->getRequestFilter() > 0)
        {
            QString strMethod = QString::fromStdString(request->GetMethod().ToString());
            QString strUrl = QString::fromStdString(request->GetURL().ToString());
            int iResourceType = request->GetResourceType();
            QString strKey;

            if (opr->findRequestFilter(strMethod, strUrl, iResourceType, strKey))
            {
                opr->pageBeforeResourceLoad(strKey, strMethod, strUrl, iResourceType);
            }
        }
    }

    return RV_CONTINUE;
}

CefRefPtr<CefResourceHandler> QCefDelegate::GetResourceHandler(CefRefPtr<CefBrowser> browser,
                                                                     CefRefPtr<CefFrame> frame,
                                                                     CefRefPtr<CefRequest> request)
{
    QCEF_DEBUG();

    return nullptr;
}

void QCefDelegate::OnResourceRedirect(CefRefPtr<CefBrowser> browser,
                                        CefRefPtr<CefFrame> frame,
                                        CefRefPtr<CefRequest> request,
                                        CefRefPtr<CefResponse> response,
                                        CefString& new_url)
{
    QCEF_DEBUG();
}

bool QCefDelegate::OnResourceResponse(CefRefPtr<CefBrowser> browser,
                                        CefRefPtr<CefFrame> frame,
                                        CefRefPtr<CefRequest> request,
                                        CefRefPtr<CefResponse> response)
{
    QCEF_DEBUG();

    return false;
}

CefRefPtr<CefResponseFilter> QCefDelegate::GetResourceResponseFilter(CefRefPtr<CefBrowser> browser,
                                                                       CefRefPtr<CefFrame> frame,
                                                                       CefRefPtr<CefRequest> request,
                                                                       CefRefPtr<CefResponse> response)
{
    QCEF_DEBUG();

    OPERATOR_CLASS * opr = m_operator.loadAcquire();
    if (opr != nullptr)
    {
        if (opr->getResponseFilter() > 0)
        {
            QString strMethod = QString::fromStdString(request->GetMethod().ToString());
            QString strUrl = QString::fromStdString(request->GetURL().ToString());
            int iResourceType = request->GetResourceType();
            QString strKey;

            if (opr->findResponseFilter(strMethod, strUrl, iResourceType, strKey))
            {
                return (new QCefStrResFilter(opr, strKey, strMethod, strUrl, iResourceType));
            }
        }
    }

    return nullptr;
}

void QCefDelegate::OnResourceLoadComplete(CefRefPtr<CefBrowser> browser,
                                                CefRefPtr<CefFrame> frame,
                                                CefRefPtr<CefRequest> request,
                                                CefRefPtr<CefResponse> response,
                                                CefResourceRequestHandler::URLRequestStatus status,
                                                int64 received_content_length)
{
    QCEF_DEBUG();

    OPERATOR_CLASS * opr = m_operator.loadAcquire();
    if (opr != nullptr)
    {
        if (opr->getRequestCompleteFilter() > 0)
        {
            QString strMethod = QString::fromStdString(request->GetMethod().ToString());
            QString strUrl = QString::fromStdString(request->GetURL().ToString());
            int iResourceType = request->GetResourceType();
            QString strKey;

            if (opr->findRequestFilter(strMethod, strUrl, iResourceType, strKey))
            {
                //request
                CefRequest::HeaderMap reqMap;
                request->GetHeaderMap(reqMap);

                QMultiMap<QString, QString> qreqMap;
                for (auto iter = reqMap.begin(); iter != reqMap.end(); ++iter)
                {
                    qreqMap.insert(QString::fromStdString(iter->first.ToString()), QString::fromStdString(iter->second.ToString()));
                }

                //response
                CefResponse::HeaderMap resMap;
                response->GetHeaderMap(resMap);

                QMultiMap<QString, QString> qresMap;
                for (auto iter = resMap.begin(); iter != resMap.end(); ++iter)
                {
                    qresMap.insert(QString::fromStdString(iter->first.ToString()), QString::fromStdString(iter->second.ToString()));
                }

                //
                opr->pageResourceLoadComplete(strKey, strMethod, strUrl, iResourceType, qreqMap, qresMap);
            }
        }
    }
}

void QCefDelegate::OnProtocolExecution(CefRefPtr<CefBrowser> browser,
                                             CefRefPtr<CefFrame> frame,
                                             CefRefPtr<CefRequest> request,
                                             bool& allow_os_execution)
{
    QCEF_DEBUG();
}



//////////////////////////////////////////////////////////////////////////
//CefDownloadHandler
void QCefDelegate::OnBeforeDownload(CefRefPtr<CefBrowser> browser,
                                      CefRefPtr<CefDownloadItem> download_item,
                                      const CefString& suggested_name,
                                      CefRefPtr<CefBeforeDownloadCallback> callback)
{
    QCEF_DEBUG();

    OPERATOR_CLASS * opr = m_operator.loadAcquire();
    if (opr != nullptr)
    {
        QString strOrgUrl = QString::fromStdString(download_item->GetOriginalUrl().ToString());
        QString strUrl = QString::fromStdString(download_item->GetURL().ToString());

        if (opr->isDownloadFile(strOrgUrl, strUrl))
        {
            CefString filePath(opr->getDownFilePath().toStdString());

            callback->Continue(filePath, false);
        }
    }
}

void QCefDelegate::OnDownloadUpdated(CefRefPtr<CefBrowser> browser,
                                           CefRefPtr<CefDownloadItem> download_item,
                                           CefRefPtr<CefDownloadItemCallback> callback)
{
    QCEF_DEBUG();

    OPERATOR_CLASS * opr = m_operator.loadAcquire();
    if (opr != nullptr)
    {
        int iDownStatus = -2;
        if (download_item->IsInProgress())
        {
            iDownStatus = 0;
        }
        else if (download_item->IsComplete())
        {
            iDownStatus = 1;
        }
        else if (download_item->IsCanceled())
        {
            iDownStatus = -1;
        }

        if (iDownStatus == 0 && opr->getSignalDownProgress() <= 0)
        {
            return;
        }

        //
        int percent = download_item->GetPercentComplete();
        int64 iReceivedBytes = download_item->GetReceivedBytes();
        int64 iTotalBytes = download_item->GetTotalBytes();
        QString strFilePath = QString::fromStdString(download_item->GetFullPath().ToString());
        QString strUrl = QString::fromStdString(download_item->GetURL().ToString());

        opr->pageDownloadUpdated(strUrl, strFilePath, iDownStatus, iTotalBytes, iReceivedBytes, percent);
    }
}
